/******************************************************************************/
/*! 
    Filename
    [Copyright]

    \file
    \namespace    
    \brief      
*/
/******************************************************************************/
/*** Includes *****************************************************************/
#include "NGame.h"
#include "NWorld.h"
#include "NDirector.h"
#include "NXmlParseMaster.h"
#include "NGameException.h"

#include "NeroCore\NSector.h"
#include "NeroCore\NLogger.h"
#include "NeroCore\NMemoryManager.h"

#include "NeroEngine\NPlatform.h"
#include "NeroEngine\NEntity.h"
#include "NeroEngine\NFileSystem.h"
#include "NeroEngine\NAudioManager.h"
#include "NeroEngine\NDebug.h"
#include "NeroEngine\NRenderThread.h"

/*** Using ********************************************************************/
using namespace Game;
using namespace Core;
using namespace Engine;
using namespace Debug;
/*** Macros *******************************************************************/
RTTI_DEFINITIONS(NGame)
/*** Constants ****************************************************************/
/*** Declarations *************************************************************/
/*** Variables ****************************************************************/
Game::NGame* GGame = NULL;
int G_Verbosity = VERBOSE_LEVEL::VERBOSE_LEVEL_HIGH;

extern std::string GScene;
/*** Implementation ***********************************************************/
/******************************************************************************/
/*! NGame :: NGame  
    \param		- void
    \return		- void
	\brief		- Default Constructor for class NGame
*/
/******************************************************************************/
NGame::NGame()
	:mIsGameClosing(false),
	 mNumEntities(0),
	 mIsInitialized(false),
	 mWorld(NULL),
	 mPlatform(NULL)
{
	if(!GGame)
	{
		GGame = this;
	}
}

/******************************************************************************/
/*! NGame :: ~NGame
    \param		- void
    \return		- void
	\brief		- Deconstructor for class NGame
*/
/******************************************************************************/
NGame::~NGame(void)
{
	MY_DELETE(mWorld);
}

/******************************************************************************/
/*! NGame :: Update

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::Update(float deltaTime)
{	
	try
	{
		GetPlatform()->Update();

		mEventQueue.Update(GetPlatform()->GetGameTime());

		NAudioManager::GetInstance()->Update(deltaTime);

		if(mWorld)
		{
			mWorld->Update(deltaTime);
		}
	}
	catch(std::exception e)
	{
		OUTLOG(e.what());
	}
}

/******************************************************************************/
/*! NGame :: Render

    \brief  
    \param  
    \return
*/
/******************************************************************************/
void NGame::Render()
{
	//throw NException("Function is not implemented");
}

void NGame::PreRender()
{
}

void NGame::PostRender()
{
}

/******************************************************************************/
/*! NGame :: Initialize

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::Initialize(const std::string& scene)
{	
	try
	{
		//Xml
		NXML::NXmlParseMaster::Initialize();
	
		//Load Scene
		LoadScene(scene);

		//Audio
		NAudioManager::Initialize();

		//Camera Director
		NDirector::Initialize();
		
		//Platform Specific Initialization
		InitializePlatform();

		//Initialize Game World
		if(mWorld)
		{
			mWorld->Initialize();
		}
	}
	catch(std::exception e)
	{
		OUTLOG(e.what());
	}
}

/******************************************************************************/
/*! NGame :: Deinitialize

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::Deinitialize()
{
	try
	{
		//Camera Director
		NDirector::Deinitialize();

		//Audio
		NAudioManager::Deinitialize();

		//Xml
		NXML::NXmlParseMaster::Deinitialize();

		DeinitializePlatform();

		if(mWorld != NULL)
		{
			mWorld->Deinitialize();
			MY_DELETE(mWorld);
			mWorld = NULL;
		}
	}
	catch(std::exception e)
	{
		OUTLOG(e.what());
	}
}
/******************************************************************************/
/*! NGame :: CreateWorld

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::CreateWorld(std::string worldName)
{
	if(mWorld == NULL)
	{
		mWorld = MY_NEW(Memory::HID_Engine,"GameWorld") NWorld();
		mWorld->GetWorldState().CurrentGame = this;
	}
}

NWorld* NGame::GetWorld()
{
	return mWorld;
}

/******************************************************************************/
/*! NGame :: AddEntityToWorld

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::AddEntityToWorld(NEntity*, const std::string&)
{
	if(mWorld == NULL)
	{
		//throw NException("Game World Has Not Been Initialized");
	}
	//mWorld->GetWorldState().CurrentSector->AddNewMemeber(entity, name);
	mNumEntities++;
}

/******************************************************************************/
/*! NGame :: GetEntity

    \brief  
    \param  
    \return
*/
/******************************************************************************/
NEntity* NGame::GetEntity(const std::string& name)
{
	NEntity* entity = NULL;
	Core::NDatum* datum = mWorld->GetWorldState().CurrentSector->Find(name);
	if(datum)
	{
		entity = datum->Get<Core::NScope*>(0)->As<NEntity>();
	}
	return entity;
}

/******************************************************************************/
/*! NGame :: GetEntity

    \brief  
    \param  
    \return
*/
/******************************************************************************/
NEntity* NGame::GetEntity(const int& index)
{
	Core::NDatum& datum = (*mWorld->GetWorldState().CurrentSector)[index];
	NEntity* entity = datum.Get<Core::NScope*>(0)->As<NEntity>();
	return entity;
}

/******************************************************************************/
/*! NGame :: GetEventQueue

    \brief  
    \param  
    \return
*/
/******************************************************************************/
NEventQueue& NGame::GetEventQueue()
{
	return mEventQueue;
}

/******************************************************************************/
/*! NGame :: EndGame

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::EndGame()
{
	StopRenderThread();
	mIsGameClosing = true;
}

/******************************************************************************/
/*! NGame :: Notify

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::Notify(NEventPublisher*, float)
{
}

/******************************************************************************/
/*! NGame :: InitializePlatform

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::InitializePlatform()
{
	if(mPlatform)
	{
		mPlatform->Initialize();
	}
}

/******************************************************************************/
/*! NGame :: DeinitializePlatform

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::DeinitializePlatform()
{
	if(mPlatform)
	{
		mPlatform->Deinitialize();
	}
}

/******************************************************************************/
/*! NGame :: SetPlatform

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::SetPlatform(Engine::NPlatform* platform)
{
	if(platform)
	{
		mPlatform = platform;
	}
}

/******************************************************************************/
/*! NGame :: GetPlatform

    \brief  

    \param  
    \return
*/
/******************************************************************************/
Engine::NPlatform* NGame::GetPlatform()
{
	if(!mPlatform )
	{
		throw Game::NGameException("NGame::GetPlatform - Platform was not set");
	}
	return mPlatform;
}

/******************************************************************************/
/*! NGame :: NumberOfEntities

    \brief  

    \param  
    \return
*/
/******************************************************************************/
int NGame::NumberOfEntities()
{
	return mNumEntities;
}

/******************************************************************************/
/*! NGame :: LoadScene

    \brief  

    \param  
    \return
*/
/******************************************************************************/
void NGame::LoadScene(std::string scene)
{
	NXML::NXmlParseMaster::GetInstance()->ParseXMl(scene.c_str());
}

bool NGame::IsClosing()
{
	return mIsGameClosing;
}

/******************************************************************************/
/*! Global :: GetGame
    \brief  
    \param  
    \return
*/
/******************************************************************************/
NGame* GetGame()
{
	extern Game::NGame* GGame;
	return GGame;
}